package com.smile.commons.gps;

import com.smile.commons.gps.domain.CoordinatePointReq;
import lombok.Data;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * 面状航线生成器
 * 根据多个经纬度点位区域生成面状航线的经纬度
 * 
 * @author System
 * @since 2024-09-18
 */
public class PlanarAirlineGenerator {

    /**
     * 地球半径（单位：米）
     */
    private static final double EARTH_RADIUS = 6378137.0;

    /**
     * 航线配置参数
     */
    @Data
    public static class AirlineConfig {
        /** 航向重叠率（百分比，如：80表示80%） */
        private Integer overlapH = 80;
        
        /** 旁向重叠率（百分比，如：60表示60%） */
        private Integer overlapW = 60;
        
        /** 飞行高度（米） */
        private BigDecimal flightHeight = new BigDecimal("120");
        
        /** 航线方向（度，0-360） */
        private Integer direction = 0;
        
        /** 测区外扩距离（米） */
        private Integer margin = 50;
        
        /** 相机焦距（毫米） */
        private Double focalLength = 24.0;
        
        /** 传感器宽度（毫米） */
        private Double sensorWidth = 36.0;
        
        /** 传感器高度（毫米） */
        private Double sensorHeight = 24.0;
        
        /** 图像宽度（像素） */
        private Integer imageWidth = 4000;
        
        /** 图像高度（像素） */
        private Integer imageHeight = 3000;
        
        /** 是否针对高德地图显示优化 */
        private Boolean gaodeOptimized = false;
    }

    /**
     * 生成面状航线
     * 
     * @param boundaryPoints 边界点列表（多边形顶点）
     * @param config 航线配置参数
     * @return 航线点列表
     */
    public static List<CoordinatePointReq> generatePlanarAirline(List<CoordinatePointReq> boundaryPoints, AirlineConfig config) {
        if (boundaryPoints == null || boundaryPoints.size() < 3) {
            throw new IllegalArgumentException("边界点数量至少需要3个");
        }

        // 1. 计算多边形外接矩形
        BoundingBox boundingBox = calculateBoundingBox(boundaryPoints);
        
        // 2. 根据外扩距离扩展边界
        if (config.getMargin() > 0) {
            boundingBox = expandBoundingBox(boundingBox, config.getMargin());
        }

        // 3. 计算地面采样距离（GSD）
        double gsd = calculateGSD(config.getFlightHeight().doubleValue(), config.getFocalLength(), config.getSensorWidth(), config.getImageWidth());
        System.out.println("gsd = " + gsd);
        // 4. 计算航线间距和拍照间距
        double lineSpacing = calculateLineSpacing(gsd, config.getSensorHeight(), config.getImageHeight(), config.getOverlapW());
        double photoSpacing = calculatePhotoSpacing(gsd, config.getSensorWidth(), config.getImageWidth(), config.getOverlapH());

        // 5. 生成航线点
        List<CoordinatePointReq> flightPath = generateFlightPath(boundingBox, boundaryPoints, config.getDirection(), lineSpacing, photoSpacing, config.getFlightHeight(), config);

        return flightPath;
    }

    /**
     * 计算多边形的外接矩形
     */
    private static BoundingBox calculateBoundingBox(List<CoordinatePointReq> points) {
        double minLat = points.get(0).getLatitude().doubleValue();
        double maxLat = points.get(0).getLatitude().doubleValue();
        double minLon = points.get(0).getLongitude().doubleValue();
        double maxLon = points.get(0).getLongitude().doubleValue();

        for (CoordinatePointReq point : points) {
            double lat = point.getLatitude().doubleValue();
            double lon = point.getLongitude().doubleValue();

            minLat = Math.min(minLat, lat);
            maxLat = Math.max(maxLat, lat);
            minLon = Math.min(minLon, lon);
            maxLon = Math.max(maxLon, lon);
        }

        return new BoundingBox(minLat, maxLat, minLon, maxLon);
    }

    /**
     * 扩展边界框
     */
    private static BoundingBox expandBoundingBox(BoundingBox box, int marginMeters) {
        // 将米转换为度数（近似计算）
        double latMargin = marginMeters / 111320.0; // 1度纬度约等于111320米
        double lonMargin = marginMeters / (111320.0 * Math.cos(Math.toRadians((box.minLat + box.maxLat) / 2)));

        return new BoundingBox(
            box.minLat - latMargin,
            box.maxLat + latMargin,
            box.minLon - lonMargin,
            box.maxLon + lonMargin
        );
    }

    /**
     * 计算地面采样距离（GSD）
     * GSD = (飞行高度 * 传感器尺寸) / (焦距 * 图像尺寸)
     */
    private static double calculateGSD(double flightHeight, double focalLength, double sensorSize, int imageSize) {
        return (flightHeight * sensorSize) / (focalLength * imageSize);
    }

    /**
     * 计算航线间距
     */
    private static double calculateLineSpacing(double gsd, double sensorHeight, int imageHeight, int overlapPercent) {
        double groundCoverage = gsd * imageHeight; // 图像覆盖的地面距离
        double overlap = overlapPercent / 100.0;
        return groundCoverage * (1 - overlap);
    }

    /**
     * 计算拍照间距
     */
    private static double calculatePhotoSpacing(double gsd, double sensorWidth, int imageWidth, int overlapPercent) {
        double groundCoverage = gsd * imageWidth; // 图像覆盖的地面距离
        double overlap = overlapPercent / 100.0;
        return groundCoverage * (1 - overlap);
    }

    /**
     * 生成飞行路径（以边框第一个点为起始点）
     * 航点严格限制在边界内，不超出边框
     */
    private static List<CoordinatePointReq> generateFlightPath(BoundingBox boundingBox, List<CoordinatePointReq> boundaryPoints, 
                                                              int direction, double lineSpacing, double photoSpacing, BigDecimal flightHeight, AirlineConfig config) {
        List<CoordinatePointReq> flightPath = new ArrayList<>();
        
        // 将角度转换为弧度
        double directionRad = Math.toRadians(direction);
        
        // 计算航线方向向量
        double dx = Math.sin(directionRad);
        double dy = Math.cos(directionRad);
        
        // 计算垂直于航线方向的向量（用于航线间距）
        double perpDx = -dy;
        double perpDy = dx;

        // 计算边界框的实际尺寸
        double boxWidth = calculateDistance(boundingBox.minLat, boundingBox.minLon, boundingBox.minLat, boundingBox.maxLon);
        double boxHeight = calculateDistance(boundingBox.minLat, boundingBox.minLon, boundingBox.maxLat, boundingBox.minLon);
        
        // 不扩展边界框，严格使用原始边界
        // 计算需要覆盖的距离
        double perpCoverageDistance = Math.abs(perpDx * boxWidth) + Math.abs(perpDy * boxHeight);
        
        // 使用适中的航线间距，确保覆盖完整但不超出边界
        double actualLineSpacing = Math.min(lineSpacing, 80.0); // 最大间距80米
        double actualPhotoSpacing = Math.min(photoSpacing, 50.0); // 最大拍照间距50米
        
        // 计算航线数量，增加一些额外航线确保覆盖
        int lineCount = (int) Math.ceil(perpCoverageDistance / actualLineSpacing) + 2;
        
        // 计算航线起始偏移，使航线居中覆盖区域
        double startOffset = -perpCoverageDistance / 2;

        // 生成航线
        for (int i = 0; i < lineCount; i++) {
            // 计算当前航线的偏移距离
            double currentOffset = startOffset + actualLineSpacing * i;
            
            // 计算航线起始点（从边界框中心开始）
            double centerLat = (boundingBox.minLat + boundingBox.maxLat) / 2;
            double centerLon = (boundingBox.minLon + boundingBox.maxLon) / 2;
            
            // 计算航线起始点
            double startLat = centerLat + perpDy * currentOffset / 111320.0;
            double startLon = centerLon + perpDx * currentOffset / (111320.0 * Math.cos(Math.toRadians(centerLat)));
            
            // 计算航线长度（覆盖整个区域但不超出太多）
            double lineLength = Math.sqrt(boxWidth * boxWidth + boxHeight * boxHeight);
            
            // 计算航线两端点
            double halfLength = lineLength / 2;
            double startLineLat = startLat - dy * halfLength / 111320.0;
            double startLineLon = startLon - dx * halfLength / (111320.0 * Math.cos(Math.toRadians(startLat)));
            double endLineLat = startLat + dy * halfLength / 111320.0;
            double endLineLon = startLon + dx * halfLength / (111320.0 * Math.cos(Math.toRadians(startLat)));

            // 在航线上生成拍照点
            int photoCount = (int) Math.ceil(lineLength / actualPhotoSpacing) + 1;
            
            List<CoordinatePointReq> linePoints = new ArrayList<>();
            
            // 沿航线生成点
            for (int j = 0; j < photoCount; j++) {
                double ratio = (double) j / Math.max(1, photoCount - 1);
                double lat = startLineLat + (endLineLat - startLineLat) * ratio;
                double lon = startLineLon + (endLineLon - startLineLon) * ratio;
                
                CoordinatePointReq point = new CoordinatePointReq();
                point.setLatitude(new BigDecimal(lat).setScale(8, RoundingMode.HALF_UP));
                point.setLongitude(new BigDecimal(lon).setScale(8, RoundingMode.HALF_UP));
                point.setHeight(flightHeight);
                
                // 严格检查点是否在多边形内部，不允许超出边界
                if (config.getGaodeOptimized() != null && config.getGaodeOptimized()) {
                    // 使用高德优化的判断方法
                    if (isPointInPolygonForGaode(point, boundaryPoints)) {
                        linePoints.add(point);
                    }
                } else {
                    // 使用标准判断方法
                    if (isPointInPolygon(point, boundaryPoints)) {
                        linePoints.add(point);
                    }
                }
            }
            
            // 如果航线上有有效点，则添加到飞行路径
            if (!linePoints.isEmpty()) {
                // 交替航线方向（蛇形飞行）
                if (i % 2 == 1) {
                    // 反转航线方向
                    List<CoordinatePointReq> reversedLine = new ArrayList<>();
                    for (int k = linePoints.size() - 1; k >= 0; k--) {
                        reversedLine.add(linePoints.get(k));
                    }
                    flightPath.addAll(reversedLine);
                } else {
                    flightPath.addAll(linePoints);
                }
            }
        }
        
        // 如果生成的航点仍然太少，使用高德地图优化的网格方法
        if (flightPath.size() < 4) {
            System.out.println("标准方法生成航点不足，切换到高德优化网格方法...");
            flightPath = generateGaodeOptimizedFlightPath(boundingBox, boundaryPoints, actualLineSpacing, actualPhotoSpacing, flightHeight);
        }

        // 重新排序航线，使其从距离边框第一个点最近的点开始
        if (!flightPath.isEmpty() && !boundaryPoints.isEmpty()) {
            flightPath = reorderFlightPathFromStartPoint(flightPath, boundaryPoints.get(0));
        }

        return flightPath;
    }
    
    /**
     * 针对高德地图显示优化的边界内点判断
     * 考虑坐标系转换误差和显示精度问题，专为内凹多边形优化
     */
    private static boolean isPointInPolygonForGaode(CoordinatePointReq point, List<CoordinatePointReq> polygon) {
        // 对于内凹多边形，使用更严格的边界判断策略
        double tolerance = 0.000005; // 约合0.5米的误差，比之前更严格
        
        // 1. 首先检查是否太接近边界（对于内凹形状，边界附近的点容易误判）
        if (isPointNearPolygonBoundary(point, polygon, tolerance * 2)) {
            return false; // 太接近边界的点直接排除
        }
        
        // 2. 使用改进的射线法进行判断
        boolean inside = isPointInPolygonImproved(point, polygon);
        
        // 3. 如果基础判断通过，再做一次安全距离检查
        if (inside) {
            return !isPointNearPolygonBoundary(point, polygon, tolerance);
        }
        
        return false;
    }
    
    /**
     * 改进的射线法，专门针对内凹多边形优化
     */
    private static boolean isPointInPolygonImproved(CoordinatePointReq point, List<CoordinatePointReq> polygon) {
        double x = point.getLongitude().doubleValue();
        double y = point.getLatitude().doubleValue();
        
        // 使用多个不同方向的射线进行检测，提高准确性
        int intersectionCount1 = countRayIntersections(x, y, polygon, 1.0, 0.0);   // 水平向右
        int intersectionCount2 = countRayIntersections(x, y, polygon, 0.0, 1.0);   // 垂直向上
        int intersectionCount3 = countRayIntersections(x, y, polygon, 1.0, 1.0);   // 45度
        int intersectionCount4 = countRayIntersections(x, y, polygon, 1.0, -1.0);  // -45度
        
        // 如果大多数射线都判定为内部，则认为点在内部
        int insideCount = 0;
        if (intersectionCount1 % 2 == 1) insideCount++;
        if (intersectionCount2 % 2 == 1) insideCount++;
        if (intersectionCount3 % 2 == 1) insideCount++;
        if (intersectionCount4 % 2 == 1) insideCount++;
        
        return insideCount >= 3; // 至少3个方向的射线都判定为内部
    }
    
    /**
     * 计算指定方向射线与多边形的交点数量
     */
    private static int countRayIntersections(double px, double py, List<CoordinatePointReq> polygon, double dirX, double dirY) {
        int intersections = 0;
        int n = polygon.size();
        
        for (int i = 0; i < n; i++) {
            int j = (i + 1) % n;
            double x1 = polygon.get(i).getLongitude().doubleValue();
            double y1 = polygon.get(i).getLatitude().doubleValue();
            double x2 = polygon.get(j).getLongitude().doubleValue();
            double y2 = polygon.get(j).getLatitude().doubleValue();
            
            // 检查射线是否与线段相交
            if (raySegmentIntersection(px, py, dirX, dirY, x1, y1, x2, y2)) {
                intersections++;
            }
        }
        
        return intersections;
    }
    
    /**
     * 检查射线是否与线段相交
     */
    private static boolean raySegmentIntersection(double rayX, double rayY, double rayDirX, double rayDirY,
                                                 double segX1, double segY1, double segX2, double segY2) {
        double segDirX = segX2 - segX1;
        double segDirY = segY2 - segY1;
        
        double denominator = rayDirX * segDirY - rayDirY * segDirX;
        
        if (Math.abs(denominator) < 1e-10) {
            return false; // 射线与线段平行
        }
        
        double t = ((segX1 - rayX) * segDirY - (segY1 - rayY) * segDirX) / denominator;
        double u = ((segX1 - rayX) * rayDirY - (segY1 - rayY) * rayDirX) / denominator;
        
        return t > 1e-10 && u >= 0 && u <= 1; // t > 0 表示交点在射线正方向，u在[0,1]表示交点在线段上
    }
    
    /**
     * 检查点是否太接近多边形边界
     */
    private static boolean isPointNearPolygonBoundary(CoordinatePointReq point, List<CoordinatePointReq> polygon, double tolerance) {
        double x = point.getLongitude().doubleValue();
        double y = point.getLatitude().doubleValue();
        
        for (int i = 0; i < polygon.size(); i++) {
            int next = (i + 1) % polygon.size();
            double x1 = polygon.get(i).getLongitude().doubleValue();
            double y1 = polygon.get(i).getLatitude().doubleValue();
            double x2 = polygon.get(next).getLongitude().doubleValue();
            double y2 = polygon.get(next).getLatitude().doubleValue();
            
            // 计算点到线段的距离
            double distance = pointToLineDistance(x, y, x1, y1, x2, y2);
            if (distance <= tolerance) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 生成严格边界内的飞行路径（针对高德地图显示优化及内凹多边形）
     */
    private static List<CoordinatePointReq> generateGaodeOptimizedFlightPath(BoundingBox boundingBox, List<CoordinatePointReq> boundaryPoints, 
                                                                             double lineSpacing, double photoSpacing, BigDecimal flightHeight) {
        List<CoordinatePointReq> flightPath = new ArrayList<>();
        
        // 对于内凹多边形，使用更严格的边界收缩策略
        double shrinkRatio = 0.0003; // 增加收缩比例到 0.03%，确保不超出边界
        double latRange = boundingBox.maxLat - boundingBox.minLat;
        double lonRange = boundingBox.maxLon - boundingBox.minLon;
        
        double shrunkMinLat = boundingBox.minLat + latRange * shrinkRatio;
        double shrunkMaxLat = boundingBox.maxLat - latRange * shrinkRatio;
        double shrunkMinLon = boundingBox.minLon + lonRange * shrinkRatio;
        double shrunkMaxLon = boundingBox.maxLon - lonRange * shrinkRatio;
        
        // 使用更小的网格间距，提高覆盖密度
        double latStep = Math.min(lineSpacing, 30.0) / 111320.0; // 最小30米间距
        double lonStep = Math.min(lineSpacing, 30.0) / (111320.0 * Math.cos(Math.toRadians((shrunkMinLat + shrunkMaxLat) / 2)));
        
        // 对于内凹多边形，使用更密集的网格扫描
        boolean evenRow = true;
        int validPoints = 0;
        int totalChecked = 0;
        
        for (double lat = shrunkMinLat; lat <= shrunkMaxLat; lat += latStep) {
            if (evenRow) {
                for (double lon = shrunkMinLon; lon <= shrunkMaxLon; lon += lonStep) {
                    totalChecked++;
                    if (addConcavePolygonPoint(flightPath, lat, lon, boundaryPoints, flightHeight)) {
                        validPoints++;
                    }
                }
            } else {
                for (double lon = shrunkMaxLon; lon >= shrunkMinLon; lon -= lonStep) {
                    totalChecked++;
                    if (addConcavePolygonPoint(flightPath, lat, lon, boundaryPoints, flightHeight)) {
                        validPoints++;
                    }
                }
            }
            evenRow = !evenRow;
        }
        
        System.out.println(String.format("高德优化网格方法：检查 %d 个点，生成 %d 个有效航点", totalChecked, validPoints));
        
        return flightPath;
    }
    
    /**
     * 为内凹多边形添加网格点（使用增强型边界检查）
     */
    private static boolean addConcavePolygonPoint(List<CoordinatePointReq> flightPath, double lat, double lon, 
                                                 List<CoordinatePointReq> boundaryPoints, BigDecimal flightHeight) {
        CoordinatePointReq point = new CoordinatePointReq();
        point.setLatitude(new BigDecimal(lat).setScale(8, RoundingMode.HALF_UP));
        point.setLongitude(new BigDecimal(lon).setScale(8, RoundingMode.HALF_UP));
        point.setHeight(flightHeight);
        
        // 使用专门针对内凹多边形优化的边界判断
        if (isPointInPolygonForGaode(point, boundaryPoints)) {
            flightPath.add(point);
            return true;
        }
        return false;
    }
    private static List<CoordinatePointReq> generateStrictBoundaryFlightPath(BoundingBox boundingBox, List<CoordinatePointReq> boundaryPoints, 
                                                                            double lineSpacing, double photoSpacing, BigDecimal flightHeight) {
        List<CoordinatePointReq> flightPath = new ArrayList<>();
        
        // 使用网格方式生成密集航点，但不扩展边界
        double latStep = Math.min(lineSpacing, 60.0) / 111320.0; // 最小60米间距
        double lonStep = Math.min(lineSpacing, 60.0) / (111320.0 * Math.cos(Math.toRadians((boundingBox.minLat + boundingBox.maxLat) / 2)));
        
        // 不扩展边界，使用原始边界框
        double minLat = boundingBox.minLat;
        double maxLat = boundingBox.maxLat;
        double minLon = boundingBox.minLon;
        double maxLon = boundingBox.maxLon;
        
        // 生成网格点
        boolean evenRow = true;
        int totalPoints = 0;
        
        for (double lat = minLat; lat <= maxLat; lat += latStep) {
            if (evenRow) {
                // 从左到右
                for (double lon = minLon; lon <= maxLon; lon += lonStep) {
                    if (addStrictBoundaryPoint(flightPath, lat, lon, boundaryPoints, flightHeight)) {
                        totalPoints++;
                    }
                }
            } else {
                // 从右到左（蛇形路径）
                for (double lon = maxLon; lon >= minLon; lon -= lonStep) {
                    if (addStrictBoundaryPoint(flightPath, lat, lon, boundaryPoints, flightHeight)) {
                        totalPoints++;
                    }
                }
            }
            evenRow = !evenRow;
        }
        
        System.out.println("严格边界网格方法生成了 " + totalPoints + " 个航点");
        
        return flightPath;
    }
    
    /**
     * 添加严格边界内的网格点
     */
    private static boolean addStrictBoundaryPoint(List<CoordinatePointReq> flightPath, double lat, double lon, 
                                                 List<CoordinatePointReq> boundaryPoints, BigDecimal flightHeight) {
        CoordinatePointReq point = new CoordinatePointReq();
        point.setLatitude(new BigDecimal(lat).setScale(8, RoundingMode.HALF_UP));
        point.setLongitude(new BigDecimal(lon).setScale(8, RoundingMode.HALF_UP));
        point.setHeight(flightHeight);
        
        // 严格检查点是否在多边形内部，不允许超出边界
        if (isPointInPolygon(point, boundaryPoints)) {
            flightPath.add(point);
            return true;
        }
        return false;
    }

    /**
     * 生成密集型飞行路径（当普通方法生成点数过少时使用）
     */
    private static List<CoordinatePointReq> generateDenseFlightPath(BoundingBox boundingBox, List<CoordinatePointReq> boundaryPoints, 
                                                                   int direction, double lineSpacing, double photoSpacing, BigDecimal flightHeight) {
        List<CoordinatePointReq> flightPath = new ArrayList<>();
        
        // 使用网格方式生成密集航点，但不扩展边界
        double latStep = Math.min(lineSpacing, 40.0) / 111320.0; // 最小40米间距
        double lonStep = Math.min(lineSpacing, 40.0) / (111320.0 * Math.cos(Math.toRadians((boundingBox.minLat + boundingBox.maxLat) / 2)));
        
        // 不扩展边界框，使用原始边界
        double minLat = boundingBox.minLat;
        double maxLat = boundingBox.maxLat;
        double minLon = boundingBox.minLon;
        double maxLon = boundingBox.maxLon;
        
        // 生成网格点
        boolean evenRow = true;
        int totalPoints = 0;
        
        for (double lat = minLat; lat <= maxLat; lat += latStep) {
            if (evenRow) {
                // 从左到右
                for (double lon = minLon; lon <= maxLon; lon += lonStep) {
                    if (addGridPoint(flightPath, lat, lon, boundaryPoints, flightHeight)) {
                        totalPoints++;
                    }
                }
            } else {
                // 从右到左（蛇形路径）
                for (double lon = maxLon; lon >= minLon; lon -= lonStep) {
                    if (addGridPoint(flightPath, lat, lon, boundaryPoints, flightHeight)) {
                        totalPoints++;
                    }
                }
            }
            evenRow = !evenRow;
        }
        
        System.out.println("密集网格方法生成了 " + totalPoints + " 个航点（严格边界内）");
        
        return flightPath;
    }
    
    /**
     * 添加网格点到飞行路径（严格边界内）
     */
    private static boolean addGridPoint(List<CoordinatePointReq> flightPath, double lat, double lon, 
                                   List<CoordinatePointReq> boundaryPoints, BigDecimal flightHeight) {
        CoordinatePointReq point = new CoordinatePointReq();
        point.setLatitude(new BigDecimal(lat).setScale(8, RoundingMode.HALF_UP));
        point.setLongitude(new BigDecimal(lon).setScale(8, RoundingMode.HALF_UP));
        point.setHeight(flightHeight);
        
        // 严格检查点是否在多边形内部，不允许超出边界
        if (isPointInPolygon(point, boundaryPoints)) {
            flightPath.add(point);
            return true;
        }
        return false;
    }

    /**
     * 重新排序航线，使其从距离指定起始点最近的航点开始
     */
    private static List<CoordinatePointReq> reorderFlightPathFromStartPoint(List<CoordinatePointReq> flightPath, CoordinatePointReq startPoint) {
        if (flightPath.isEmpty()) {
            return flightPath;
        }

        // 找到距离起始点最近的航点索引
        int closestIndex = findClosestPointIndex(flightPath, startPoint);
        
        // 重新排序航线
        List<CoordinatePointReq> reorderedPath = new ArrayList<>();
        
        // 从最近的点开始，添加到列表末尾的所有点
        for (int i = closestIndex; i < flightPath.size(); i++) {
            reorderedPath.add(flightPath.get(i));
        }
        
        // 添加从开头到最近点之前的所有点
        for (int i = 0; i < closestIndex; i++) {
            reorderedPath.add(flightPath.get(i));
        }
        
        return reorderedPath;
    }

    /**
     * 找到距离指定点最近的航点索引
     */
    private static int findClosestPointIndex(List<CoordinatePointReq> points, CoordinatePointReq targetPoint) {
        int closestIndex = 0;
        double minDistance = calculateDistanceFromCoordinatePoints(points.get(0), targetPoint);
        
        for (int i = 1; i < points.size(); i++) {
            double distance = calculateDistanceFromCoordinatePoints(points.get(i), targetPoint);
            if (distance < minDistance) {
                minDistance = distance;
                closestIndex = i;
            }
        }
        
        return closestIndex;
    }

    /**
     * 计算两个坐标点之间的距离（米）
     */
    private static double calculateDistanceFromCoordinatePoints(CoordinatePointReq point1, CoordinatePointReq point2) {
        return calculateDistance(
            point1.getLatitude().doubleValue(), 
            point1.getLongitude().doubleValue(),
            point2.getLatitude().doubleValue(), 
            point2.getLongitude().doubleValue()
        );
    }

    /**
     * 计算两点间距离（米）
     */
    private static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        double lat1Rad = Math.toRadians(lat1);
        double lat2Rad = Math.toRadians(lat2);
        double deltaLat = Math.toRadians(lat2 - lat1);
        double deltaLon = Math.toRadians(lon2 - lon1);

        double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
                   Math.cos(lat1Rad) * Math.cos(lat2Rad) *
                   Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        return EARTH_RADIUS * c;
    }

    /**
     * 判断点是否在多边形内部或附近（更宽松的条件）
     */
    private static boolean isPointInOrNearPolygon(CoordinatePointReq point, List<CoordinatePointReq> polygon, double tolerance) {
        // 首先检查是否在多边形内部
        if (isPointInPolygon(point, polygon)) {
            return true;
        }
        
        // 检查是否在边界附近
        if (isPointOnPolygonBoundary(point, polygon, tolerance)) {
            return true;
        }
        
        // 检查是否在多边形的外扩缓冲区内
        double x = point.getLongitude().doubleValue();
        double y = point.getLatitude().doubleValue();
        
        // 计算点到多边形的最短距离
        double minDistance = Double.MAX_VALUE;
        
        for (int i = 0; i < polygon.size(); i++) {
            int next = (i + 1) % polygon.size();
            double x1 = polygon.get(i).getLongitude().doubleValue();
            double y1 = polygon.get(i).getLatitude().doubleValue();
            double x2 = polygon.get(next).getLongitude().doubleValue();
            double y2 = polygon.get(next).getLatitude().doubleValue();
            
            double distance = pointToLineDistance(x, y, x1, y1, x2, y2);
            minDistance = Math.min(minDistance, distance);
        }
        
        // 如果距离小于容差值，则认为在缓冲区内
        return minDistance <= tolerance;
    }

    /**
     * 判断点是否在多边形内部（改进的射线法，提高精度）
     */
    private static boolean isPointInPolygon(CoordinatePointReq point, List<CoordinatePointReq> polygon) {
        double x = point.getLongitude().doubleValue();
        double y = point.getLatitude().doubleValue();
        
        boolean inside = false;
        int j = polygon.size() - 1;
        
        // 使用高精度计算
        for (int i = 0; i < polygon.size(); i++) {
            double xi = polygon.get(i).getLongitude().doubleValue();
            double yi = polygon.get(i).getLatitude().doubleValue();
            double xj = polygon.get(j).getLongitude().doubleValue();
            double yj = polygon.get(j).getLatitude().doubleValue();
            
            // 防止数值精度问题，使用双精度计算
            if (Math.abs(yi - yj) < 1e-10) {
                // 水平线段，特殊处理
                if (Math.abs(y - yi) < 1e-10 && x >= Math.min(xi, xj) && x <= Math.max(xi, xj)) {
                    return true; // 点在边界上
                }
            } else if (((yi > y) != (yj > y))) {
                // 计算交点的x坐标
                double intersectX = xi + (xj - xi) * (y - yi) / (yj - yi);
                if (x < intersectX) {
                    inside = !inside;
                }
            }
            j = i;
        }
        
        return inside;
    }

    /**
     * 判断点是否在多边形边界上
     */
    private static boolean isPointOnPolygonBoundary(CoordinatePointReq point, List<CoordinatePointReq> polygon, double tolerance) {
        double x = point.getLongitude().doubleValue();
        double y = point.getLatitude().doubleValue();
        
        for (int i = 0; i < polygon.size(); i++) {
            int next = (i + 1) % polygon.size();
            double x1 = polygon.get(i).getLongitude().doubleValue();
            double y1 = polygon.get(i).getLatitude().doubleValue();
            double x2 = polygon.get(next).getLongitude().doubleValue();
            double y2 = polygon.get(next).getLatitude().doubleValue();
            
            // 计算点到线段的距离
            double distance = pointToLineDistance(x, y, x1, y1, x2, y2);
            if (distance <= tolerance) {
                return true;
            }
        }
        
        return false;
    }

    /**
     * 计算点到线段的距离
     */
    private static double pointToLineDistance(double px, double py, double x1, double y1, double x2, double y2) {
        double dx = x2 - x1;
        double dy = y2 - y1;
        
        if (dx == 0 && dy == 0) {
            // 线段退化为点
            return Math.sqrt((px - x1) * (px - x1) + (py - y1) * (py - y1));
        }
        
        double t = ((px - x1) * dx + (py - y1) * dy) / (dx * dx + dy * dy);
        t = Math.max(0, Math.min(1, t)); // 限制t在[0,1]范围内
        
        double closestX = x1 + t * dx;
        double closestY = y1 + t * dy;
        
        return Math.sqrt((px - closestX) * (px - closestX) + (py - closestY) * (py - closestY));
    }

    /**
     * 边界框类
     */
    @Data
    private static class BoundingBox {
        private final double minLat;
        private final double maxLat;
        private final double minLon;
        private final double maxLon;

        public BoundingBox(double minLat, double maxLat, double minLon, double maxLon) {
            this.minLat = minLat;
            this.maxLat = maxLat;
            this.minLon = minLon;
            this.maxLon = maxLon;
        }
    }
}